#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <semaphore.h>
#include "log.h"
#include "planificador.h"
#include "Prueba-ArchConfig.h"
#include "FuncionesPPD.h"
#include "FuncionesPlanificador.h"
#include "I_O_Disco.h"
#include "serializable.h"


void planifica(void* config){
	datosConfigPPD* planificador = (datosConfigPPD*) config;
	tInfo* Nodo;
	int32_t priVes = 1;
	t_log * LogFile;

	t_CHS *NodoCHS;
	NodoCHS = malloc (sizeof(t_CHS));

	if (strcmp((char*) planificador->algoritmoPlanificacion, "F-SCAN") == 0 ){
		while(1){

			sem_wait(&semContadorL);
			pthread_mutex_lock(&sem_Lista);
			Lista2 = Lista;
			ListaRev2 = ListaRev;
			Lista = NULL;
			ListaRev = NULL;
			sem_init(&semContadorL,0,0);
			pthread_mutex_unlock(&sem_Lista);

			RecorrerLista(Lista2);
			Nodo= SCAN();

			while(Nodo != NULL){

				 if(priVes != 1){
					 if((strcmp((char*) planificador->logs, "ENABLE") == 0 )||(estado == M_CONSOLE_ENABLE)){
					t_CHS *NodoCHS1;
					NodoCHS1 = malloc(sizeof(t_CHS));
					pasaLogicoReal(Nodo->sector,NodoCHS1 );
					LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, estado);
					log_info(LogFile, "", "%s%i:%i","Proximo Sector : ",NodoCHS1->Cilindro ,NodoCHS1->Sector);
					log_destroy(LogFile);
					free(NodoCHS1);
				 }
				 }
				 priVes = 0;



				if ( Nodo->type == 1 || Nodo->type == msgSyncRead){
					ifType1(Nodo, NodoCHS, planificador);
				}
				if ( Nodo->type == 2){
					ifType2(Nodo, NodoCHS, planificador);
				}
				if ( Nodo->type == 3){
					//consola//
					ifType3(Nodo, NodoCHS, planificador);
				}

				free(Nodo->dato);
				free(Nodo);
				actualizarCHS();
				if(Lista2 != NULL){

					RecorrerLista(Lista2);
					Nodo= SCAN();
				}
				else Nodo = NULL;
				}
			//free(Nodo);
			//actualizarCHS();

			}
	}
	if (strcmp((char*) planificador->algoritmoPlanificacion, "SSTF") == 0 ){
		while(1){
			 Nodo= SSTF();
			 if((priVes != 1)){
				 if((strcmp((char*) planificador->logs, "ENABLE") == 0 )||(estado == M_CONSOLE_ENABLE)){
				t_CHS *NodoCHS1;
				NodoCHS1 = malloc(sizeof(t_CHS));
				pasaLogicoReal(Nodo->sector,NodoCHS1 );
				LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, estado);
				log_info(LogFile, "", "%s%i:%i","Proximo Sector : ",NodoCHS1->Cilindro ,NodoCHS1->Sector);
				log_destroy(LogFile);
				free(NodoCHS1);
				 }
			 }

			 priVes =0;


			if ( Nodo->type == 1 || Nodo->type == msgSyncRead){
				ifType1(Nodo, NodoCHS, planificador);

				}
			if ( Nodo->type == 2){
				ifType2(Nodo, NodoCHS, planificador);
				}
			if ( Nodo->type == 3){
				//consola//
				ifType3(Nodo, NodoCHS, planificador);
			}

			free(Nodo->dato);
			free(Nodo);
			actualizarCHS();
		}
	}


	return;
}



void ifType1(tInfo *Nodo,t_CHS* NodoCHS, datosConfigPPD* arch ){
	Message aMsg;
	Serializable_t aSerializable;
	estado = M_CONSOLE_DISABLE;
	int32_t timeLectura = (int32_t) atoi((char*)arch->timeLectura) * 1000;

	t_CHS *NodoCHS1;
	NodoCHS1 = malloc(sizeof(t_CHS));
	pasaLogicoReal(Nodo->sector,NodoCHS1 );

	if (strcmp((char*) arch->logs, "ENABLE") == 0 ){

	t_log *LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, M_CONSOLE_DISABLE);
	log_info(LogFile, "", "%s%i:%i","Posicion actual : ",CHSActual->Cilindro ,CHSActual->Sector);
	log_destroy(LogFile);

	LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, M_CONSOLE_DISABLE);
	log_info(LogFile, "", "%s%i:%i","Sector Solicitado : ",NodoCHS1->Cilindro ,NodoCHS1->Sector);
	log_destroy(LogFile);

	secRecorridos(NodoCHS1,M_CONSOLE_DISABLE);
	}
	CHSActual->Cilindro= NodoCHS1->Cilindro;
	CHSActual->Sector = NodoCHS1->Sector;
	free(NodoCHS1);
	usleep(timeLectura);
//	printf("llego hasta antes del leerSector\n");
	int32_t sector = Nodo->sector;
	aMsg.type= Nodo->type;
	aMsg.sectorRequest = (uint32_t)Nodo->sector;
	aMsg.contentSize= 512;
	aMsg.auxiliar = Nodo->auxiliar;
	char* buffer;
	buffer = malloc(512);
	leerSectorMAP(punteroMmap , sector,buffer);
	aMsg.content= buffer;
	Serialize_Message(&aSerializable,aMsg);
	send(Nodo->socket , aSerializable.Data ,aSerializable.Size, MSG_CONFIRM );
	//Deserialize_Message(&aMsg, aSerializable);
	Serializable_Free(&aSerializable);
	free(buffer);
//	close(Nodo->socket);
}

void ifType2(tInfo *Nodo,t_CHS* NodoCHS, datosConfigPPD* arch ){
	Message aMsg;
	Serializable_t aSerializable;
	estado = M_CONSOLE_DISABLE;
	time_t timeEscritura = (time_t) atoi((char*)arch->timeEscritura) / 100;
	//Escritura de un sector//


	t_CHS *NodoCHS1;
	NodoCHS1 = malloc(sizeof(t_CHS));
	pasaLogicoReal(Nodo->sector,NodoCHS1 );

	if (strcmp((char*) arch->logs, "ENABLE") == 0 ){
	t_log *LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, M_CONSOLE_DISABLE);
	log_info(LogFile, "", "%s%i:%i","Posicion actual : ",CHSActual->Cilindro ,CHSActual->Sector);
	log_destroy(LogFile);

	LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, M_CONSOLE_DISABLE);
	log_info(LogFile, "", "%s%i:%i","Sector Solicitado : ",NodoCHS1->Cilindro ,NodoCHS1->Sector);
	log_destroy(LogFile);

	secRecorridos(NodoCHS1, M_CONSOLE_DISABLE);
	}
	CHSActual->Cilindro= NodoCHS1->Cilindro;
	CHSActual->Sector = NodoCHS1->Sector;
	free(NodoCHS1);
	sleep(timeEscritura);
	escribirSectorMAP(punteroMmap , Nodo->sector,Nodo->dato);

	if(Nodo->socket != -1){
	aMsg.type= 2;
	aMsg.sectorRequest = Nodo->sector;
	aMsg.auxiliar = Nodo->auxiliar;
	aMsg.contentSize= 0;
	aMsg.content= NULL;
	Serialize_Message(&aSerializable,aMsg);
	send(Nodo->socket , aSerializable.Data ,aSerializable.Size, MSG_CONFIRM );
//	Deserialize_Message(&aMsg, aSerializable);
	Serializable_Free(&aSerializable);
//	close(Nodo->socket);
	}
}

void ifType3(tInfo *Nodo,t_CHS* NodoCHS, datosConfigPPD* arch ){


	estado = M_CONSOLE_ENABLE;

	t_CHS *NodoCHS1;
	NodoCHS1 = malloc(sizeof(t_CHS));
	pasaLogicoReal(Nodo->sector,NodoCHS1 );

	t_log *LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, M_CONSOLE_ENABLE);
	log_info(LogFile, "", "%s%i:%i","Posicion actual : ",CHSActual->Cilindro ,CHSActual->Sector);
	log_destroy(LogFile);

	LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, M_CONSOLE_ENABLE);
	log_info(LogFile, "", "%s%i:%i","Sector Solicitado : ",NodoCHS1->Cilindro ,NodoCHS1->Sector);
	log_destroy(LogFile);

	secRecorridos(NodoCHS1, M_CONSOLE_ENABLE);

	CHSActual->Cilindro= NodoCHS1->Cilindro;
	CHSActual->Sector = NodoCHS1->Sector;
	free(NodoCHS1);
	pthread_mutex_lock(&sem_Tracer);
	Tracer = Tracer -1;
	pthread_mutex_unlock(&sem_Tracer);


}

 void secRecorridos(t_CHS *NodoCHS, e_console_mode estado){
	 int32_t CantidadSec=0;
	 int32_t CantidadCil=0;
	 t_log *LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, estado);
	 log_info(LogFile, "", "%s","Sectores Recorridos ");
//	 log_destroy(LogFile);

//	 printf("Sectores Recorridos: ");
	 if(CHSActual->Cilindro != NodoCHS->Cilindro){
		 while(CHSActual->Cilindro !=NodoCHS->Cilindro ){
			 if(CHSActual->Cilindro < NodoCHS->Cilindro){
				 CHSActual->Cilindro = CHSActual->Cilindro +1;
				 log_info(LogFile, "", "%i:%i",CHSActual->Cilindro, CHSActual->Sector);
//				 printf("%i:%i, ",CHSActual->Cilindro, CHSActual->Sector );
			 }
			 else{
				 CHSActual->Cilindro = CHSActual->Cilindro -1;
				 log_info(LogFile, "", "%i:%i",CHSActual->Cilindro, CHSActual->Sector);
//				 printf("%i:%i, ",CHSActual->Cilindro, CHSActual->Sector );
			 }
			 CantidadCil = CantidadCil +1;
		 }
	 }

	 while(CHSActual->Sector != NodoCHS->Sector){
		 CHSActual->Sector = CHSActual->Sector +1;
		 if(CHSActual->Sector > CHStot->Sector) CHSActual->Sector = 0;
		 log_info(LogFile, "", "%i:%i",CHSActual->Cilindro, CHSActual->Sector);
//		 printf("%i:%i, ",CHSActual->Cilindro, CHSActual->Sector );
		 CantidadSec = CantidadSec +1;
	 }
	 log_destroy(LogFile);

	 int32_t timeConsumido;
	 timeConsumido = (CantidadCil * atoi((char*)archPPD->timeSaltoPista)) +
			 (CantidadSec * timeEntreSector );//timePorSecor
	 LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, estado);
	 log_info(LogFile, "", "%s%i%s","TiempoConsumido : ",timeConsumido ," ms");
	 log_destroy(LogFile);

//	 printf("\nTiempoConsumido: %i ms\n",timeConsumido );
 }

 void RecorrerLista(tNodo* lis){
	 tNodo* aux;
	 tInfo* auxSub;
	 int32_t contaPedidos=0;

	 if (strcmp((char*) archPPD->logs, "ENABLE") == 0 ){
		 aux = lis;
		 t_log *LogFile = log_create("ProcesoPlanificadorDisco", LogFileName, INFO, M_CONSOLE_DISABLE);
		 log_info(LogFile, "", "%s","Cola de Pedidos: ");
//		 printf("Cola de Pedidos: [ ");
		 while (aux != NULL){
			 auxSub=aux->Info;
			 while (auxSub != NULL){
				 contaPedidos = contaPedidos + 1;
				 log_info(LogFile, "", "%i",auxSub->sector);
//				 printf("%i,", auxSub->sector);
				 auxSub=auxSub->Sig;
			 }
			 aux=aux->Sig;
		 }
		 log_info(LogFile, "", "%s %i","Tamaño:",contaPedidos);
		 log_destroy(LogFile);
//		 printf(" ] Tamaño: %i\n",contaPedidos);
	 }

 }
